package org.zhuzx.util;

import com.alibaba.fastjson.JSON;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.util.Assert;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 次级通用工具类，作为GeneralUtil的辅助。
 * 归属原则：需要依赖第三方jar包的工具方法，但提供的功能与GeneralUtil一样，属于最基础、最通用的层级。
 * @author zhuzx 2022/5/18
 */
public class SecondaryUtil {

	/**
	 * 从map中提取一个任意嵌套深度的值转化为指定类型的对象，每多传一个key就往里面多深入一级。
	 * 需要注意，除了最后一个key，前面的其它key对应的值都必须是Map。
	 */
	@SuppressWarnings("unchecked")
	public static <T> T extractObject(Map<String,Object> map, Class<T> cla, String... keys) {
		Assert.notEmpty(keys, "至少需要传入一个key");
		int i = 0;
		for (; i < keys.length - 1; i++) {
			map = (Map<String,Object>) map.get(keys[i]);
		}
		Object obj = map.get(keys[i]);
		if (obj == null) {
			return null;
		}
		return cla.isInstance(obj) ? (T) obj : JSON.parseObject(JSON.toJSONString(obj), cla);
	}

	/**
	 * 获取该类中所有属性的swagger注解说明文本，也就是ApiModelProperty注解的value值（一般源自表字段注释）。<br>
	 * 1、包括本身声明的和继承的，若父类中有同名属性则以子类的为准。<br>
	 * 2、即使字段上未标注swagger注解也会给出键名（值为null），保证Map中列出了所有字段。
	 * @return 字段名作为key，注释值作为value，返回按反射顺序的LinkedHashMap。
	 */
	public static Map<String, String> getFieldSwaggerValues(Class<?> clazz) {
		String cacheKey = SecondaryUtil.class.getSimpleName() + ".getFieldSwaggerValues-" + clazz.getName();
		return UnifiedConstants.getRuntimeConstant(cacheKey, () -> {
			Map<String,String> map = new LinkedHashMap<>();
			RttiUtil.getAllFields(clazz).values().forEach(field -> {
				ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
				String value = (annotation == null) ? null : annotation.value();
				map.put(field.getName(), value);
			});
			return map;
		});
	}

	/**
	 * 获取该类中所有属性的swagger注解，也就是ApiModelProperty对象。<br>
	 * 1、包括本身声明的和继承的，若父类中有同名属性则以子类的为准。<br>
	 * 2、仅限于标注了swagger注解的属性，无注解的属性不会出现在Map中（没有这个key）。
	 */
	public static Map<String, ApiModelProperty> getFieldSwaggerAnnotations(Class<?> clazz) {
		String cacheKey = SecondaryUtil.class.getSimpleName() + ".getFieldSwaggerAnnotations-" + clazz.getName();
		return UnifiedConstants.getRuntimeConstant(cacheKey, () -> {
			Map<String,ApiModelProperty> map = new LinkedHashMap<>();
			RttiUtil.getAllFields(clazz).values().forEach(field -> {
				ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
				if (annotation != null) {
					map.put(field.getName(), annotation);
				}
			});
			return map;
		});
	}
	
}